# Copyright 2010-2025 Google LLC
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

load("@bazel_skylib//rules:common_settings.bzl", "bool_flag")
load("@bazel_skylib//rules:copy_file.bzl", "copy_file")
load("@protobuf//bazel:cc_proto_library.bzl", "cc_proto_library")
load("@protobuf//bazel:proto_library.bzl", "proto_library")
load("@protobuf//bazel:py_proto_library.bzl", "py_proto_library")
load("@rules_cc//cc:defs.bzl", "cc_library")

package(default_visibility = ["//visibility:public"])

exports_files(["model_exporter_swig_helper.h"])

# OSS solvers
bool_flag(
    name = "with_bop",
    build_setting_default = True,
)

config_setting(
    name = "use_bop",
    flag_values = {
        ":with_bop": "true",
    },
)

bool_flag(
    name = "with_cbc",
    build_setting_default = False,
)

config_setting(
    name = "use_cbc",
    flag_values = {
        ":with_cbc": "true",
    },
)

bool_flag(
    name = "with_clp",
    build_setting_default = False,
)

config_setting(
    name = "use_clp",
    flag_values = {
        ":with_clp": "true",
    },
)

bool_flag(
    name = "with_cp_sat",
    build_setting_default = True,
)

config_setting(
    name = "use_cp_sat",
    flag_values = {
        ":with_cp_sat": "true",
    },
)

bool_flag(
    name = "with_glop",
    build_setting_default = True,
)

config_setting(
    name = "use_glop",
    flag_values = {
        ":with_glop": "true",
    },
)

bool_flag(
    name = "with_glpk",
    build_setting_default = False,
)

config_setting(
    name = "use_glpk",
    flag_values = {
        ":with_glpk": "true",
    },
)

bool_flag(
    name = "with_highs",
    build_setting_default = False,
)

config_setting(
    name = "use_highs",
    flag_values = {
        ":with_highs": "true",
    },
)

bool_flag(
    name = "with_pdlp",
    build_setting_default = True,
)

config_setting(
    name = "use_pdlp",
    flag_values = {
        ":with_pdlp": "true",
    },
)

bool_flag(
    name = "with_scip",
    build_setting_default = True,
)

config_setting(
    name = "use_scip",
    flag_values = {
        ":with_scip": "true",
    },
)

# Prorietary solvers
bool_flag(
    name = "with_cplex",
    build_setting_default = False,
)

config_setting(
    name = "use_cplex",
    flag_values = {
        ":with_cplex": "true",
    },
)

proto_library(
    name = "linear_solver_proto",
    srcs = ["linear_solver.proto"],
    deps = ["//ortools/util:optional_boolean_proto"],
)

cc_proto_library(
    name = "linear_solver_cc_proto",
    deps = [":linear_solver_proto"],
)

py_proto_library(
    name = "linear_solver_py_pb2",
    visibility = ["//visibility:public"],
    deps = [":linear_solver_proto"],
)

# You can include the interfaces to different solvers by invoking '--define'
# flags. By default GLOP, BOP, SCIP, GUROBI, and CP-SAT interface are included.
#
# For instance, if you want to use the GLPK solver, build with
# '--define USE_GLPK=' (or add it to your bazel.rc file). This will download,
# build and link to GLPK.
cc_library(
    name = "linear_solver",
    srcs = [
        "gurobi_interface.cc",
        "linear_expr.cc",
        "linear_solver.cc",
        "linear_solver_callback.cc",
        "sat_interface.cc",
        "xpress_interface.cc",
    ] + select({
        ":use_bop": ["bop_interface.cc"],
        "//conditions:default": [],
    }) + select({
        ":use_cbc": ["cbc_interface.cc"],
        "//conditions:default": [],
    }) + select({
        ":use_clp": ["clp_interface.cc"],
        "//conditions:default": [],
    }) + select({
        ":use_glop": [
            "glop_interface.cc",
            "glop_utils.cc",
        ],
        "//conditions:default": [],
    }) + select({
        ":use_glpk": ["glpk_interface.cc"],
        "//conditions:default": [],
    }) + select({
        ":use_highs": ["highs_interface.cc"],
        "//conditions:default": [],
    }) + select({
        ":use_pdlp": ["pdlp_interface.cc"],
        "//conditions:default": [],
    }) + select({
        ":use_scip": [
            "scip_callback.cc",
            "scip_interface.cc",
        ],
        "//conditions:default": [],
    }) + select({
        ":use_cplex": ["cplex_interface.cc"],
        "//conditions:default": [],
    }),
    hdrs = [
        "linear_expr.h",
        "linear_solver.h",
        "linear_solver_callback.h",
    ] + select({
        ":use_glop": ["glop_utils.h"],
        "//conditions:default": [],
    }) + select({
        ":use_scip": [
            "scip_callback.h",
            "scip_helper_macros.h",
        ],
        "//conditions:default": [],
    }),
    copts = [] + select({
        ":use_bop": ["-DUSE_BOP"],
        "//conditions:default": [],
    }) + select({
        ":use_cbc": ["-DUSE_CBC"],
        "//conditions:default": [],
    }) + select({
        ":use_clp": ["-DUSE_CLP"],
        "//conditions:default": [],
    }) + select({
        ":use_glop": ["-DUSE_GLOP"],
        "//conditions:default": [],
    }) + select({
        ":use_glpk": ["-DUSE_GLPK"],
        "//conditions:default": [],
    }) + select({
        ":use_highs": ["-DUSE_HIGHS"],
        "//conditions:default": [],
    }) + select({
        ":use_pdlp": ["-DUSE_PDLP"],
        "//conditions:default": [],
    }) + select({
        ":use_scip": ["-DUSE_SCIP"],
        "//conditions:default": [],
    }) + select({
        ":use_cplex": ["-DUSE_CPLEX"],
        "//conditions:default": [],
    }),
    deps = [
        ":linear_solver_cc_proto",
        ":model_exporter",
        ":model_validator",
        "//ortools/base",
        "//ortools/base:accurate_sum",
        "//ortools/base:dynamic_library",
        "//ortools/base:hash",
        "//ortools/base:logging",
        "//ortools/base:map_util",
        "//ortools/base:status_macros",
        "//ortools/base:stl_util",
        "//ortools/base:timer",
        "//ortools/gurobi:environment",
        "//ortools/gurobi:gurobi_util",
        "//ortools/linear_solver/proto_solver:gurobi_proto_solver",
        "//ortools/linear_solver/proto_solver:sat_proto_solver",
        "//ortools/port:file",
        "//ortools/port:proto_utils",
        "//ortools/sat:cp_model_cc_proto",
        "//ortools/sat:cp_model_solver",
        "//ortools/sat:lp_utils",
        "//ortools/util:fp_utils",
        "//ortools/util:lazy_mutable_copy",
        "//ortools/xpress:environment",
        "@abseil-cpp//absl/status",
        "@abseil-cpp//absl/status:statusor",
        "@abseil-cpp//absl/strings",
        "@abseil-cpp//absl/synchronization",
        "@abseil-cpp//absl/types:optional",
    ] + select({
        ":use_bop": [
            "//ortools/bop:bop_parameters_cc_proto",
            "//ortools/bop:integral_solver",
        ],
        "//conditions:default": [],
    }) + select({
        ":use_glop": [
            "//ortools/glop:lp_solver",
            "//ortools/glop:parameters_cc_proto",
            "//ortools/linear_solver/proto_solver:glop_proto_solver",
        ],
        "//conditions:default": [],
    }) + select({
        ":use_glpk": [
            "//ortools/glpk:glpk_env_deleter",
            "@glpk",
        ],
        "//conditions:default": [],
    }) + select({
        ":use_pdlp": [
            "//ortools/linear_solver/proto_solver:pdlp_proto_solver",
            "//ortools/pdlp:primal_dual_hybrid_gradient",
            "//ortools/pdlp:solve_log_cc_proto",
            "//ortools/pdlp:solvers_cc_proto",
        ],
        "//conditions:default": [],
    }) + select({
        ":use_scip": [
            "//ortools/gscip:legacy_scip_params",
            "//ortools/linear_solver/proto_solver:scip_proto_solver",
            "@scip",
        ],
        "//conditions:default": [],
    }),
)

cc_library(
    name = "model_validator",
    srcs = ["model_validator.cc"],
    hdrs = ["model_validator.h"],
    visibility = ["//visibility:public"],
    deps = [
        ":linear_solver_cc_proto",
        "//ortools/base",
        "//ortools/base:accurate_sum",
        "//ortools/base:map_util",
        "//ortools/port:file",
        "//ortools/port:proto_utils",
        "//ortools/util:fp_utils",
        "//ortools/util:lazy_mutable_copy",
        "@abseil-cpp//absl/container:flat_hash_map",
        "@abseil-cpp//absl/container:flat_hash_set",
        "@abseil-cpp//absl/status",
        "@abseil-cpp//absl/status:statusor",
        "@abseil-cpp//absl/strings",
        "@abseil-cpp//absl/strings:str_format",
        "@abseil-cpp//absl/types:optional",
    ],
)

cc_library(
    name = "scip_helper_macros",
    hdrs = ["scip_helper_macros.h"],
    deps = [
        "//ortools/base:status_macros",
        "@abseil-cpp//absl/status",
        "@abseil-cpp//absl/strings:str_format",
    ],
)

# Model exporter that can write MPS and LP file formats from an MPModelProto.
cc_library(
    name = "model_exporter",
    srcs = ["model_exporter.cc"],
    hdrs = ["model_exporter.h"],
    deps = [
        ":linear_solver_cc_proto",
        "//ortools/base",
        "//ortools/base:file",
        "//ortools/base:hash",
        "//ortools/base:map_util",
        "//ortools/base:status_macros",
        "//ortools/util:fp_utils",
        "@abseil-cpp//absl/container:flat_hash_set",
        "@abseil-cpp//absl/status",
        "@abseil-cpp//absl/status:statusor",
        "@abseil-cpp//absl/strings",
        "@abseil-cpp//absl/strings:str_format",
    ],
)

cc_binary(
    name = "solve",
    srcs = ["solve.cc"],
    deps = [
        ":linear_solver",
        ":linear_solver_cc_proto",
        "//ortools/base",
        "//ortools/base:file",
        "//ortools/lp_data:lp_parser",
        "//ortools/lp_data:model_reader",
        "//ortools/lp_data:mps_reader",
        "//ortools/lp_data:sol_reader",
        "@abseil-cpp//absl/status",
        "@abseil-cpp//absl/status:statusor",
        "@abseil-cpp//absl/time",
    ],
)

cc_library(
    name = "solve_mp_model",
    srcs = ["solve_mp_model.cc"],
    hdrs = ["solve_mp_model.h"],
    visibility = ["//visibility:public"],
    deps = [
        ":linear_solver",
        ":linear_solver_cc_proto",
        "//ortools/util:solve_interrupter",
    ],
)
